#include <stdio.h>
#include <sys/select.h>
#include "myServer.h"
#include "thread_manger.h"
#include "net.h"
#include "process.h"
#include "file_manger.h"
#include "log.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <poll.h>
#include <sys/epoll.h>
#include "error_handle.h"
#include <signal.h>
#include <fcntl.h>


#define TABLE_SIZE  20

#define SERVER_MODE 3

#if (SERVER_MODE == 0)
    #define SELECT_LOOP
#elif (SERVER_MODE == 1)
    #define THREAD_LOOP
#elif (SERVER_MODE == 2)
    #define POLL_LOOP
#elif (SERVER_MODE == 3)
    #define EPOLL_LOOP
#elif (SERVER_MODE == 4)
    #define ASYNC_IO
#endif

#define MAX_CONNECTIONS 50

typedef struct {
    int server_socket;
    u32 ip_addr;
    u32 port;
    int accept_socket;
}myServer;

typedef struct {
    pthread_t thread_id;
    int client_socket;
}client_t;

HashTable *hash_table;
threadpool_t pool;
myServer server;

#if 0
#include "my_timer.h"
my_timer_t heartbeat_timer;
void heartbeat_timer_isr(unsigned long arg) {
    DBG("GEM\n");
}
#endif


extern void process(int socket);


#ifdef SELECT_LOOP
void select_loop(myServer *m_server) {
    //初始化线程池
    pool.handle_client = process;
    threadpool_init(&pool);
    DBG("thread pool init\n");

    fd_set master_set, working_set;

    // 初始化主文件描述符集
    FD_ZERO(&master_set);

    // 监听套接字绑定到master_set字符集
    FD_SET(m_server->server_socket, &master_set);

    int max_fd = m_server->server_socket;

    /*
    *当监听到可读事件时:
    *1.如果是监听套接字则接受新的连接并将其添加到文件描述符集中；
    *2.如果是已连接套接字，则将对应的文件描述符作为任务添加到线程池中。
    */

    for (; ;) {
        memcpy(&working_set, &master_set, sizeof(master_set));
        int activity = select(max_fd + 1, &working_set, NULL, NULL, NULL);
        if (activity < 0) {
            perror("select error");
            break;
        }
        else if (activity > 0) {
            for (int i = 0; i <= max_fd; i++) {
                if (FD_ISSET(i, &working_set)) {
                    DBG("socket id:%d\n", i);
                    if (i == m_server->server_socket) {
                        DBG("new client\n");
                        //是监听socket
                        int new_socket = net_accept(m_server->server_socket);
                        DBG("new socket id:%d\n", new_socket);
                        if (new_socket > 0) {
                            FD_SET(new_socket, &master_set);
                            if (new_socket > max_fd) {
                                max_fd = new_socket;
                            }
                        }
                    } else {
                        //是连接socket
                        //将IO事件添加到线程池任务队列
                        DBG("new task\n");
                        task_t task = {.sock = i};
                        threadpool_add_task(&pool, task);
                    }
                }
            }
        }
    }

    // 销毁线程池
    threadpool_destroy(&pool);
}
#endif

#ifdef THREAD_LOOP
void thread_function(void *args) {
    client_t *client = (client_t *)args;
    for (;;) {
        process(client->client_socket);
    }
    
}

void thread_loop(myServer *m_server) {
    for (;;) {
        client_t *client = (client_t *)malloc(sizeof(client_t));
        client->client_socket = net_accept(m_server->server_socket);
        DBG("new socket id:%d\n", client->client_socket);
        if (client->client_socket > 0) {
            pthread_create((pthread_t *)&client->thread_id, NULL, thread_function, (void *)client);
        }
    }
}
#endif

#ifdef POLL_LOOP
    void poll_loop(myServer *m_server) {
        pool.handle_client = process;
        threadpool_init(&pool);
        DBG("thread pool init\n");

        struct pollfd fds[MAX_CONNECTIONS];
        fds[0].fd = m_server->server_socket;
        fds[0].events = POLLIN;
        int nfds = 1;

        for (;;) {
            int poll_count = poll(fds, nfds, -1);
            if (poll_count == -1) {
                perror("poll error:");
                exit(EXIT_FAILURE);
            }

            // 检查服务器socket是否准备好接受连接
            if (fds[0].revents & POLLIN) {
                int new_socket = net_accept(m_server->server_socket);
                if (new_socket == -1) {
                    perror("accept");
                    exit(EXIT_FAILURE);
                }

                // 将新连接的socket添加到fds数组
                fds[nfds].fd = new_socket;
                fds[nfds].events = POLLIN;
                nfds++;

                printf("New connection, socket fd is %d, ip is \n", new_socket);
            }

            //检查所有连接的客户端是否有数据可读
            for (int i = 1; i < nfds; i++) {
                if (fds[i].revents & POLLIN) {
                    DBG("new task\n");
                    task_t task = {.sock = fds[i].fd};
                    threadpool_add_task(&pool, task);
                }
            }
        }
        // 销毁线程池
        threadpool_destroy(&pool);
    }

#endif


#ifdef EPOLL_LOOP
    #define MAX_EVENTS 50

    void epoll_loop(myServer *m_server) {
        int epoll_fd;
        struct epoll_event events[MAX_EVENTS];
        struct epoll_event event;

        pool.handle_client = process;
        threadpool_init(&pool);
        DBG("thread pool init\n");

        epoll_fd = epoll_create(MAX_EVENTS);
        if (epoll_fd == -1) {
            perror("epoll_create");
            exit(EXIT_FAILURE);
        }

        // 添加监听的socket到epoll实例
        event.data.fd = m_server->server_socket;
        event.events = EPOLLIN;
        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, m_server->server_socket, &event) == -1) {
            perror("epoll_ctl: listen_sock");
            exit(EXIT_FAILURE);
        }

        // 循环处理事件
        while (1) {
            int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
            if (nfds == -1) {
                perror("epoll_wait");
                exit(EXIT_FAILURE);
            }

            for (int n = 0; n < nfds; ++n) {
                if (events[n].data.fd == m_server->server_socket) {
                    // 处理新的连接
                    int new_socket = net_accept(m_server->server_socket);
                    if (new_socket == -1) {
                        perror("accept");
                        exit(EXIT_FAILURE);
                    }

                    // 将新连接的socket添加到epoll实例
                    event.data.fd = new_socket;
                    event.events = EPOLLIN; // 边缘触发模式
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_socket, &event) == -1) {
                        perror("epoll_ctl: new_socket");
                        exit(EXIT_FAILURE);
                    }
                } else {
                    // 处理已连接socket的事件
                    if (events[n].events & EPOLLIN) {
                        DBG("new task\n");
                        task_t task = {.sock = events[n].data.fd};
                        threadpool_add_task(&pool, task);
                    }
                }
            }
        }
        // 销毁线程池
        threadpool_destroy(&pool);
    }

#endif

#ifdef ASYNC_IO
    #define MAX_EVENTS 50
    int epoll_fd;

    void io_handler(int sig, siginfo_t *info, void *context) {
        // 处理新的连接
        struct epoll_event event;
        int new_socket = net_accept(server.server_socket);
        if (new_socket == -1) {
            perror("accept");
            return;
        }

        // 将新连接的socket添加到epoll实例
        event.data.fd = new_socket;
        event.events = EPOLLIN; // 边缘触发模式
        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_socket, &event) == -1) {
            perror("epoll_ctl: new_socket");
            return;
        }
    }

    void async_loop(myServer *m_server) {
        struct epoll_event events[MAX_EVENTS];

        pool.handle_client = process;
        threadpool_init(&pool);
        DBG("thread pool init\n");

        epoll_fd = epoll_create(MAX_EVENTS);
        if (epoll_fd == -1) {
            perror("epoll_create");
            exit(EXIT_FAILURE);
        }

        struct sigaction sa;
        int flag;
        flag = fcntl(m_server->server_socket, F_GETFL); //先获取原来的 flag
        flag |= O_NONBLOCK; //将 O_ASYNC 标志添加到 flag
        fcntl(m_server->server_socket, F_SETFL, flag); //重新设置 flag

        flag |= O_ASYNC;
        fcntl(m_server->server_socket, F_SETFL, flag);

        /* 设置异步 I/O 的所有者 */
        fcntl(m_server->server_socket, F_SETOWN, getpid());

        /* 指定实时信号 SIGRTMIN 作为异步 I/O 通知信号 */
        fcntl(m_server->server_socket, F_SETSIG, SIGRTMIN);

        /* 为实时信号 SIGRTMIN 注册信号处理函数 */
        sa.sa_sigaction = io_handler;
        sa.sa_flags = SA_SIGINFO;
        sigemptyset(&sa.sa_mask);
        sigaction(SIGRTMIN, &sa, NULL);

        // 循环处理事件
        while (1) {
            int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
            if (nfds == -1) {
                perror("epoll_wait");
                exit(EXIT_FAILURE);
            }

            for (int n = 0; n < nfds; ++n) {
                // 处理已连接socket的事件
                if (events[n].events & EPOLLIN) {
                    DBG("new task\n");
                    task_t task = {.sock = events[n].data.fd};
                    threadpool_add_task(&pool, task);
                }
            }
        }
        // 销毁线程池
        threadpool_destroy(&pool);
    }

#endif


int main(int argc, char **argv) {
    DBG("start server ....\n");

    //初始化读写锁，读写锁数量和文件的数量一致
    if (argc < 1) {
        ERR("argc < 1\n");
        return 0;
    }

    server.ip_addr = 0x0A0B05F3;
    server.port = 5594;

    //建立哈希表，管理文件,文件名不包含路径
    hash_table = createHashTable();

    //初始化哈希表
    DBG("dir is %s\n", argv[1]);
    DIR *d;
    struct dirent *dir;
    d = opendir(argv[1]);
    if (d) {
        while ((dir = readdir(d)) != NULL) {
            if (strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0) {
                DBG("%s\n", dir->d_name);
                file_lock_t *data = (file_lock_t *)malloc(sizeof(file_lock_t));
                memcpy(data->file_name, dir->d_name, strlen(dir->d_name));
                pthread_rwlock_init(&data->rwlock, NULL);
                insertHashTable(hash_table, data);
            }
        }
        closedir(d);
    } else {
        perror("无法打开目录");
        return 0;
    }
    DBG("hash table init success\n");

    //初始化socket
    server.server_socket = net_init(server.ip_addr, server.port);
    if (server.server_socket == -1) {
        ERR("net init error\n");
        return 0;
    }
    else {
        DBG("waiting client\n");
    }

    //初始化错误处理模块
    error_handle_init();

#if 0
    //初始化心跳
    heartbeat_timer.timer_isr = &heartbeat_timer_isr;
    heartbeat_timer.arg = (void*)&server.port;  //测试
    heartbeat_timer.time_cnt = 8000;
    timer_init(1, &heartbeat_timer);
#endif


#ifdef SELECT_LOOP
    select_loop(&server);
#endif

#ifdef THREAD_LOOP
    thread_loop(&server);
#endif

#ifdef POLL_LOOP
    poll_loop(&server);
#endif

#ifdef EPOLL_LOOP
    epoll_loop(&server);
#endif

#ifdef ASYNC_IO
    async_loop(&server);
#endif


    // 关闭监听socket
    close(server.server_socket);

    return 0;
}

